The Null Variable

The system variable !NULL is a special variable of type Undefined. Unlike a variable that is truly undefined, the value !NULL can be assigned to other variables and used in comparisons.

Assignment Syntax

Use any of the following to assign the value !NULL to a variable:

variable = !NULL

variable = [ ]

variable = { }

!NULL can be assigned to an existing variable, undefining it and freeing its memory.

A = 10

A = !NULL

PRINT, A

IDL Prints:

!NULL

Comparison

The !NULL variable is equivalent to:

Use the comparison operators EQ and NE to determine whether a variable has a defined value. (Null pointers and null objects have type Pointer and Objref, respectively, but have no defined values.)

For example, suppose the variable U has not been defined in the current IDL session. Then:

PRINT, U EQ !NULL

IDL prints:

1

showing that U has no defined value.

As another example:

p = PTR_NEW(5)

PTR_FREE, p

PRINT, p EQ !NULL

IDL prints:

1

showing that p now refers to a null pointer.

Similarly, for objects:

obj = IDL_Container()

obj.Cleanup

PRINT, obj EQ !NULL

IDL prints:

1

Assigning Function Return Values

To discard the return value from a function, assign it to !NULL. For example, suppose you wanted to find the subscripts of both the minimum and maximum values in an array using the MAX function. In the following statement:

!NULL = MAX(array, subscript_max, SUBSCRIPT_MIN=subscript_min)

the MAX function returns the subscripts of both the maximum and minimum values in the subscript_max and subscript_min variables, discarding the return value (the actual value of the largest element).

Null Values As Array Elements

Null values are ignored when they appear as array elements. For example:

array = [3.0, !NULL, 2.5, 1.9, !NULL, 0.7]

PRINT, array & HELP, array

IDL prints:

3.00000    2.50000    1.90000    0.700000

ARRAY      FLOAT     = Array[4]

As a result, a variable set equal to !NULL can be thought of as an empty element in an array specification. Thinking of a null variable in this way makes it easy to add variables to an array without first checking to ensure that the array is defined. For example, you might use code like the following when building an array variable from values determined at runtime:

array = [ ]

WHILE some_condition DO BEGIN

   IF some_other_condition THEN array = [array, new_element]

   ...

ENDWHILE

Here, the fact that we intialize the variable array to the value !NULL eliminates the need to test whether array is defined in each iteration of the WHILE loop. On the first iteration, array is equal to !NULL, and serves as an empty element that is ignored after the first variable with a defined value is added.

Similarly, if we want to construct an array by adding values in another dimension, an array containing only a null value can serve as a placeholder for an entire dimension in the array:

array = [ ]

WHILE some_condition DO BEGIN

   IF some_other_condition THEN array = [[array], [new_array]]

   ...

ENDWHILE

Here we end up creating a two-dimensional array, with each iteration adding a new array to the second dimension.

Note: The value !NULL cannot be used as a “missing value” placeholder in an array. Array elements equal to !NULL are ignored entirely, as if they were not present at all.

Null Values As Subscripts

When indexing into an array, if any of the subscripts are equal to !NULL, then the result is !NULL. For example:

array = [3.0, 2.5, 1.9, 0.7]

HELP, array[!NULL]

IDL prints:

<Expression> UNDEFINED = !NULL

As another example, using a multi-dimensional array:

array = FINDGEN(5,10,20)

HELP, array[2:3, !NULL, *]

IDL prints:

<Expression> UNDEFINED = !NULL

This is especially useful when the array appears on the left-hand side of an assignment, as the assignment is then ignored. For example:

array = FINDGEN(5,10,20)

indices = WHERE(array LT 0, /NULL)

array[indices] = -1

PRINT, MIN(array)

IDL prints:

0.000000

Since none of the elements were negative, the WHERE with /NULL returned !NULL as the result. This !NULL was then ignored when the assignment was performed. For more examples of using WHERE with !NULL, see the topic on Conditionally Altering Array Elements.

Null Values as Structures

The CREATE_STRUCT function will treat a !NULL argument as an anonymous structure with no fields. This makes it easy to add fields and values to a stucture using CREATE_STRUCT without first checking to ensure that the structure is defined. For example, you might use code like the following when building a structure variable from the contents of an array at runtime:

struct = { }

FOREACH element, array, index DO BEGIN

   fieldname = 'Field'+STRTRIM(index,2)

   some_value = some_operation_on(element)

   struct = CREATE_STRUCT(struct, fieldname, some_value)

ENDFOREACH

Here, the fact that we intialize struct to the value !NULL eliminates the need to test whether struct is defined in each iteration of the FOREACH loop. On the first iteration, struct is equal to !NULL, and serves as an anonymous structure with no fields, allowing an additional field to be added on each iteration.

Note: The value of a structure field cannot be set to !NULL.

Null Values in Pointers

When creating an IDL pointer variable, the value !NULL may be used as a placeholder to indicate that this is a valid pointer, whose value has not yet been assigned. For example, with an invalid pointer:

p = PTR_NEW()

print, *p

IDL throws the following error:

% Unable to dereference NULL pointer: P.

% Execution halted at: $MAIN$

Now, using !NULL as the value:

p = PTR_NEW(!NULL)

print, *p

IDL prints:

!NULL

Note: The ALLOCATE_HEAP keyword to PTR_NEW and PTRARR is equivalent to assigning the !NULL value to the pointers.

Null Value as an Input Argument

The !NULL value is useful for assignment, comparison, and for array concatenation. In most other cases, the !NULL value is treated as an undefined variable. For example, in routine calls:

f = FFT(!NULL)

IDL throws the following error:

% FFT: Expression must be an array in this context: <UNDEFINED>.

% Execution halted at: $MAIN$

Similarly, when trying to convert a !NULL value to a different type:

x = FIX(!NULL)

IDL throws the following error:

% FIX: Variable is undefined: <UNDEFINED>.

% Execution halted at: $MAIN$

The same error occurs when trying to convert a !NULL value to a string:

x = STRING(!NULL)

IDL throws the following error:

% STRING: Variable is undefined: <UNDEFINED>.

% Execution halted at: $MAIN$

The following table lists the cases where !NULL is accepted as an input argument:

Routine

Result

ARG_PRESENT

0

HASH indexing

!NULL

HELP

"<Expression> UNDEFINED = !NULL"

IDL_Container::Remove

Quietly returns

ISA

0

ISA with /NULL keyword

1

KEYWORD_SET

0

LIST indexing

!NULL

N_ELEMENTS

0

OBJ_ISA

0

OBJ_VALID

0

PRINT

"!NULL"

PTR_VALID

0

SIZE

[0, 0, 0]

In all other routines, IDL will throw an "undefined variable" error.

Using Null Values for Keywords

You can also pass in !NULL for keyword values.

In most cases, passing in !NULL as a keyword value will cause the calling routine to quietly ignore the keyword (as if it was not passed in at all). However, you may wish to write a routine that handles !NULL keyword values differently. The following rules are used when !NULL is passed as a keyword value:

1. If the keyword is handled directly by the called routine, then the keyword value will be set equal to !NULL. The called routine could use ISA(/NULL) to test for this, and take appropriate action (either ignore the keyword or do something else).

2. If the keyword is handled as part of _REF_EXTRA, then the keyword value will also be set to !NULL. The routine could use SCOPE_VARFETCH to retrieve this value, or pass the keyword on to other routines.

3. If the keyword is handled as part of _EXTRA, then the keyword value will not be included in the _EXTRA structure, and will be treated just as if the keyword was never passed in.

See Keyword Inheritance for the differences between _REF_EXTRA and _EXTRA.